package com.xishu.controller;

import com.xishu.annotation.valid.Admin;
import com.xishu.annotation.valid.MethodValidator;
import com.xishu.aop.Validator;
import com.xishu.bo.CompanyAndUser;
import com.xishu.client.EmailClient;
import com.xishu.config.Config;
import com.xishu.config.Constant;
import com.xishu.dao.jpa.UserDao;
import com.xishu.entity.Company;
import com.xishu.entity.User;
import com.xishu.entity.customer.CompanyConfig;
import com.xishu.entity.customer.Quota;
import com.xishu.entity.plat.GlobalSetting;
import com.xishu.entity.plat.UserCompanyMapping;
import com.xishu.entity.shop.Shop;
import com.xishu.response.ResponseData;
import com.xishu.response.ResponseStatus;
import com.xishu.response.VerifyUtil;
import com.xishu.service.*;
import com.xishu.util.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.validator.routines.EmailValidator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;

import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Optional;

import static com.xishu.response.ResponseStatus.*;

@Api(description = "公司信息")
@RestController
public class CompanyController implements Tools {
    private static Logger logger = LoggerFactory.getLogger(CompanyController.class);
    private static CommonService commonService = CommonService.getInstance();
    private static GlobalService globalService = GlobalService.getInstance();


    @ApiOperation(value = "注册商家")
    @PostMapping(value = ("/register"), produces = ("application/json;charset=UTF-8"))
    @MethodValidator(mustLogin = false)
    public ResponseData register(@RequestBody Company company) throws Exception {
        GlobalSetting globalSetting = globalService.getGlobalSetting();
        String address = globalSetting.getAddress();
        String city = globalSetting.getCity();
        String companyWebsite = globalSetting.getCompanyWebsite();
        String emailAddress = globalSetting.getEmailAddress();

        User user = ServletUtil.getUser();
        VerifyUtil.isEmpty(company.getEmail(), company.getName(), company.getContactUser(), company.getPhone1());

        //不是超级管理员，则要把公司的校验信息清空
        if (!UserService.getInstance().isAdmin(user)) {
            company.setEmailValid(null);
            company.setPrivilegeList(null);
        }

        //判断邮件是否已经存在了
        UserDao userDao = BeanUtil.getBean(UserDao.class);
        String email = company.getEmail();
        VerifyUtil.verify(() -> EmailValidator.getInstance().isValid(email), ResponseStatus.ACCOUNT_MUST_BE_EMAIL);

        User userEmail = UserService.getInstance().findUserByEmail(email);
        VerifyUtil.verify(() -> userEmail == null, ResponseStatus.EMAIL_EXITS);

        User userDaoByName = UserService.getInstance().findUserByName(email);
        VerifyUtil.verify(() -> userDaoByName == null, ResponseStatus.EMAIL_EXITS);

        //查询公司是否存在，如果存在了，并且已经是激活状态，则报错，说明公司已经存在了
        Company companyInDb = CompanyService.getInstance().findCompanyByName(company.getName());

        ResponseData responseData = ResponseData.emptyResponse();
        if (companyInDb == null) {
            logger.info("company not exist");
            initCompany(company);

            //前面已经校验过了公司名称，以及邮箱，这里不再做校验
            responseData = CommonService.getInstance().createObject(company, null, false, null);
        } else if (companyInDb.getPass() == null) {
            initCompany(company);
            logger.info("the company is active");

            //如果当前邮件跟一开始的邮件不一样了，那么报错，写明公司已存在
            if (!equals(companyInDb.getEmail(), email)) {
                VerifyUtil.throwError(ResponseStatus.COMPANY_EXIST);
            }

            //已经存在的一个公司，但是还未激活，说明是多次注册,那么更新数据
            BeanUtils.copyProperties(company, companyInDb, "id");
            commonService.save(companyInDb);
        } else {
            //已经存在的一个公司,并且已经激活了
            VerifyUtil.throwError(ResponseStatus.COMPANY_EXIST);
        }

        //同时发送邮件，是发送的邮件的对应的唯一KEY
        String emailCode = MongoId.generateId();
        JRedisUtil.setKV(emailCode, company.getEmail() + "#" + emailCode);
        //30分钟过后失效
        JRedisUtil.expire(emailCode, 30 * 60);
        //添加临时的CODE
        JRedisUtil.setKV(String.format("%s.register.code", email), emailCode);
        logger.info("set email {} the code {}", email, emailCode);
        JRedisUtil.expire(String.format("%s.register.code", email), 30 * 60);

        Config config = Config.getInstance();

        String validAddress = config.getEndPoint() + "/register/valid/" + AES.encrypt(emailCode);
        logger.info("validAddress is {}", validAddress);

        String showUrl = config.getEndPoint() + "/manage/index.html#/zcszmm?code=" + AES.encrypt(emailCode);
        String logoUrl = PlatService.getInstance().getLogoUrl();

        String title = "Welcome to DoLA - Please Verify Your Email. 歡迎注冊DoLA – 請驗證您的電郵。";

        String content = String.format("<!DOCTYPE html>\n" + "<html lang=\"en\">\n" + "<head>\n" + "    <meta charset=\"UTF-8\">\n" + "    <title>Title</title>\n" + "</head>\n" + "<body>\n" + "<div style=\"padding-right: 10%%\" align=\"right\"><img style=\"width: 100px;height: 100px;\" src=\"%s\"></div>\n" + "<div style=\"padding-left: 10%%\">\n" + "    <div>Hi %s,\n" + "        <div>\n" + "            <br/>\n" + "            Thanks for signing up for DoLA POS. We're here to help you digitalize and automate your restaurant business.\n" + "            To\n" + "            proceed with your application, please verify your email by clicking the button below:\n" + "            <br/>\n" + "            <br/>\n" + "            您好 %s，<br/>\n" + "            感謝您注冊DoLA POS。爲了完成您的賬戶申請，请點擊以下按鈕來驗證您的電郵：\n" + "            <br/>\n" + "            <br/>\n" + "            <br/>\n" + "            <div align=\"center\">\n" + "                <div style=\"width: 150px;height: 90px;text-align: center;\">\n" + "                    <div>\n" + "                        <a href=\"%s\" style=\"text-decoration:none; \">\n" + "                            <div style=\"width: 100%%;height: 100%%;background-color: #4793A3;border-width: 0px; border-radius:15px; cursor: pointer\">\n" + "                                <div style=\"padding-top:10%%;padding-bottom: 10%%;color: white\">Verify your email</div>\n" + "                                <div style=\"padding-bottom: 10%%;color: white\">點擊驗證</div>\n" + "                            </div>\n" + "                        </a>\n" + "                    </div>\n" + "                </div>\n" + "            </div>\n" + "            <br/>\n" + "            <br/>\n" + "            <br/>\n" + "            If you didn’t request this, please ignore this email. 如果您并沒有注冊DoLA，請忽略這封電郵。\n" + "            <br/>\n" + "            <br/>\n" + "            <br/>\n" + "        </div>\n" + "        <div align=\"center\">\n" + "            <div style=\"color: #808080\">"+address+"<br/>\n" + "                "+city+"<br/>\n" + "            </div>\n" + "            <div style=\"color: #4793A3;text-decoration: none !important;\">"+emailAddress+" |\n" + "               "+companyWebsite+"\n" + "            </div>\n" + "        </div>\n" + "    </div>\n" + "</div>\n" + "</body>\n" + "</html>\n", logoUrl, email, email, showUrl);

        logger.info("title is {}, content is {}", title, content);

        EmailClient.getInstance().sendEmail(company.getEmail(), title, content);

        return responseData;
    }

    private void initCompany(@RequestBody Company company) throws IllegalAccessException {
        ZhEnService.getInstance().dealZhEn(company);
        company.setPass(null);
        //将地址转化成ID
        String addressId = AreaService.getInstance().areaNameToInt(company.getCompanyAddress());
        company.setCompanyAddress(addressId);
        company.setAddressId(addressId);
    }

    @ApiOperation(value = "验证商家的邮件，验证通过后，创建商家账号")
    @MethodValidator(mustLogin = false)
    @GetMapping(value = ("/register/valid/{code}"), produces = ("application/json;charset=UTF-8"))
    public ResponseData validCompanyEmail(@PathVariable("code") String code) throws Exception {
        String emailCodeDecrypt = AES.decrypt(code);
        VerifyUtil.isEmpty(emailCodeDecrypt);
        String emailCodeInCache = JRedisUtil.getKV(emailCodeDecrypt);

        VerifyUtil.verify(() -> isNotEmpty(emailCodeInCache), ResponseStatus.EMAIL_EXPIRE);
        String[] strings = emailCodeInCache.split("#");
        String email = strings[0];

        //获取当前的email的CODE,如果不一样的，那么判断失效
        String currentRegisterCode = JRedisUtil.getKV(String.format("%s.register.code", email));
        logger.info("current code is {}", currentRegisterCode);
        VerifyUtil.verify(() -> isNotEmpty(currentRegisterCode), ResponseStatus.EMAIL_EXPIRE);
        VerifyUtil.verify(() -> equals(currentRegisterCode, emailCodeDecrypt), ResponseStatus.EMAIL_EXPIRE);

        //通过email查询账号，如果已经存在了，说明已经注册过了
        User userInDb = UserService.getInstance().findUserByEmail(email);
        VerifyUtil.verify(() -> userInDb == null, ResponseStatus.USER_ACTIVE);

        //添加商家账号
        User user = null;
        try {
            //修改商户的验证信息
            Company reqCompany = new Company();
            reqCompany.setEmail(email);
            Company company = CommonService.getInstance().searchOne(reqCompany);
            company.setEmailValid(true);
            CommonService.getInstance().directSave(company);

            //将用户信息返回
            //同时将验证码发送给客户端
            //打个标记，写在session里面,超时后用户可以通过找回密码再设置密码
            user = new User();
            user.setEmail(email);
            user.setName(email);
            user.setCompanyManager(true);
            user.setCompanyId(company.getId());
            CommonService.getInstance().createObject(user);
            ServletUtil.setUserId(user);

            ServletUtil.setSessionAttribute(Constant.RESET_PASSWORD_EMAIL, email);

            //添加账号与公司的映射关系
            UserCompanyMapping userCompanyMapping = new UserCompanyMapping();
            userCompanyMapping.setUserId(user.getId());
            userCompanyMapping.setCompanyId(company.getId());
            userCompanyMapping.setUserName(user.getName());
            userCompanyMapping.setCompanyName(company.getName());
            commonService.createObject(userCompanyMapping);

            return CommonService.getInstance().createResponse(user);
        } catch (Exception e) {
            //已经存在了，先不处理，以避免
            logger.error("e", e);
        }

        return ResponseData.emptyResponse();
    }

    @ApiOperation(value = "修改商家开通状态")
    @Admin
    @PutMapping(value = ("/company/status/modify"), produces = ("application/json;charset=UTF-8"))
    public ResponseData modifyPassStatus(@RequestBody Company reqCompany) throws Exception {
        Company companyInDb = CommonService.getInstance().findEntity(reqCompany.getId(), Company.class);
        VerifyUtil.verify(() -> companyInDb != null);

        //开通，修改餐厅
        //将对应的账号的账号修改成可以使用，并且绑定账号与餐厅的关系
        if (getBoolean(reqCompany.getPass())) {
            //给用户添加餐厅绑定关系
            String email = companyInDb.getEmail();
            User user = null;

            if (email != null) {
                logger.info("will find email {}", email);
                UserService.getInstance().findUserByEmail(email);
            }

            if (user == null) {
                logger.info("can not find the email, will find the user name {}", email);
                user = UserService.getInstance().findUserByName(email);
            }

            if (user != null) {
                logger.info("user is {}", user);
                MappingService.getInstance().createUserCompanyMapping(user.getId(), reqCompany.getId());
                user.setStatus(Constant.USER_STATUS_OK);
                CommonService.getInstance().save(user);
            } else {
                logger.info("can not find the user , may the data is old {}", email);
            }

            //给餐厅绑定用户绑定关系
            companyInDb.setPass(true);
            companyInDb.setOperatePassTime(DateUtil.formatDate(System.currentTimeMillis()));

            CommonService.getInstance().save(companyInDb);
        } else if (reqCompany.getPass() != null) {
            //不开通，只是修改餐厅的状态
            companyInDb.setOperatePassTime(DateUtil.formatDate(System.currentTimeMillis()));
            companyInDb.setPass(false);
            CommonService.getInstance().save(companyInDb);
        }
           //需要保存空字符串
        if (reqCompany.getPrintCompanyName()!=null){
            logger.info("will modify print companyName to {}", reqCompany.getPrintCompanyName());
            companyInDb.setPrintCompanyName(reqCompany.getPrintCompanyName());
            CommonService.getInstance().save(companyInDb);
        }

        //添加在线终端数量设置
        if (reqCompany.getOnlineTouchDeviceNumber() != null) {
            logger.info("will modify company online touch device number to {}", reqCompany.getOnlineTouchDeviceNumber());
            companyInDb.setOnlineTouchDeviceNumber(reqCompany.getOnlineTouchDeviceNumber());
            CommonService.getInstance().save(companyInDb);
        }

        if (reqCompany.getShopNumbers() != null) {
            logger.info("will modify company shop numbers to {}", reqCompany.getShopNumbers());
            companyInDb.setShopNumbers(reqCompany.getShopNumbers());
            CommonService.getInstance().save(companyInDb);
        }

        if (reqCompany.getUserNumbers() != null) {
            logger.info("will modify company user numbers to {}", reqCompany.getUserNumbers());
            companyInDb.setUserNumbers(reqCompany.getUserNumbers());
            CommonService.getInstance().save(companyInDb);
        }

        if (reqCompany.getOpenTableDirect() != null) {
            logger.info("will modify open table direct {}", reqCompany.getOpenTableDirect());
            companyInDb.setOpenTableDirect(reqCompany.getOpenTableDirect());
            CommonService.getInstance().save(companyInDb);
        }

        if (reqCompany.getPrinterDelay() != null) {
            companyInDb.setPrinterDelay(reqCompany.getPrinterDelay());
            CommonService.getInstance().save(companyInDb);

            //如果关闭延时打印，那么所有分店均关闭延时打印
            if (!reqCompany.getPrinterDelay()) {
                Long companyId = companyInDb.getId();
                List<Shop> shopList = ShopService.getInstance().findShopListByCompanyId(companyId);
                for (Shop shop : shopList) {
                    shop.getShopConfig().setPrinterDelay(false);
                    commonService.save(shop);
                }
            }
        }

        Boolean partPay_b = reqCompany.getPartPay_b();

        if (partPay_b != null) {
            companyInDb.setPartPay_b(partPay_b);
            CommonService.getInstance().save(companyInDb);

            //如果关闭分菜分钱，那么所有分店均关闭分菜分钱
            if (!partPay_b) {
                Long companyId = companyInDb.getId();
                List<Shop> shopList = ShopService.getInstance().findShopListByCompanyId(companyId);
                for (Shop shop : shopList) {
                    shop.getShopConfig().setPartPay_b(false);
                    commonService.save(shop);
                }
            }
        }

        Boolean partPay_c = reqCompany.getPartPay_c();
        if (partPay_c != null) {
            companyInDb.setPartPay_c(partPay_c);
            CommonService.getInstance().save(companyInDb);

            //如果关闭分菜分钱，那么所有分店均关闭分菜分钱
            if (!partPay_c) {
                Long companyId = companyInDb.getId();
                List<Shop> shopList = ShopService.getInstance().findShopListByCompanyId(companyId);
                for (Shop shop : shopList) {
                    shop.getShopConfig().setPartPay_c(false);
                    commonService.save(shop);
                }
            }
        }

        Boolean itemAdvancedSetting = reqCompany.getItemAdvancedSetting();
        if (itemAdvancedSetting != null) {
            companyInDb.setItemAdvancedSetting(reqCompany.getItemAdvancedSetting());
            CommonService.getInstance().save(companyInDb);
        }
        //是否开启自动关闭店铺
        if (reqCompany.getAutoCloseShop() != null) {
            companyInDb.setAutoCloseShop(reqCompany.getAutoCloseShop());
            CommonService.getInstance().save(companyInDb);
        }
        //自动关闭店铺的时间
        if (reqCompany.getAutoCloseShopDate() != null) {
            //判断是否修改了自动关闭的时间
            if (!equals(companyInDb.getAutoCloseShopDate(), reqCompany.getAutoCloseShopDate())) {
                List<Shop> shopListInDb = null;

                try {
                    shopListInDb = ShopService.getInstance().findShopListByCompanyId(companyInDb.getCompanyId());
                } catch (Exception e) {
                    logger.error("no abnormal", e);
                }

                logger.info("modified the automatic shutdown time {}", reqCompany.getAutoCloseShopDate());
                //修改了时间就删除redis里面的自动关闭店铺的shopId key
                for (Shop shop : shopListInDb) {
                    String shopKey = String.valueOf("AutoClose:" + shop.getId()) + Constant.AUTO_CLOSE_SHOPID_TO_KEY;
                    //现判断是否有key
                    boolean exists = JRedisUtil.exists(shopKey);
                    if (exists) {
                        logger.info("delete redis prevent repeated closing shop to key");
                        JRedisUtil.delKV(shopKey);
                    }
                }
            }

            logger.info("close shop time {}", reqCompany.getAutoCloseShopDate());
            companyInDb.setAutoCloseShopDate(reqCompany.getAutoCloseShopDate());
            CommonService.getInstance().save(companyInDb);
        }

        //是否开启跟换支付方式
        if (reqCompany.getWhetherOpenPayment() != null) {
            companyInDb.setWhetherOpenPayment(reqCompany.getWhetherOpenPayment());
            CommonService.getInstance().save(companyInDb);
        }

        //是否开启小票的最后的说明，只有超级管理员能看
        if (reqCompany.getOpenReceiptExplain() != null) {
            companyInDb.setOpenReceiptExplain(reqCompany.getOpenReceiptExplain());
            CommonService.getInstance().save(companyInDb);
        }


        return ResponseData.emptyResponse();
    }

    @ApiOperation(value = "查询商家列表")
    @MethodValidator(mustLogin = false)
    @PutMapping(value = ("/company"), produces = ("application/json;charset=UTF-8"))
    public ResponseData search(@RequestBody Company company) throws Exception {
        company.setSortField(new String[]{"createTime"});
        company.setSortType("DESC");
        Config config = Config.getInstance();

        return CommonService.getInstance().searchResponse(company, (Company t) -> {
            t.setVisitAddress(config.getEndPoint() + "/bfront/index.html#/login");

            if (getBoolean(company.getQueryBindUser())) {
                List<UserCompanyMapping> userCompanyMappingList = MappingService.getInstance().searchMappingUser(t.id);
                t.setUserCompanyMappingList(userCompanyMappingList);
            }

            //如果不存在会员等级，那么添加
            if (t.getCompanyConfig() == null) {
                CompanyConfig companyConfig = new CompanyConfig();
                t.setCompanyConfig(companyConfig);
                commonService.setDefaultValue(t.getCompanyConfig());
            }
        });
    }

    @Admin
    @ApiOperation(value = "创建商家，同时创建用户，只有超级管理员才可以调用")
    @PostMapping(value = ("/company"), produces = ("application/json;charset=UTF-8"))
    public ResponseData createCompanyAndUser(@RequestBody CompanyAndUser companyAndUser) throws Exception {
        Company company = companyAndUser.getCompany();
        ZhEnService.getInstance().dealZhEn(company);
        VerifyUtil.verify(() -> isNotEmpty(company.getName()));

        //判断商家是否存在
        Company companyInDb = CompanyService.getInstance().findCompanyByName(company.getName());
        VerifyUtil.verify(() -> companyInDb == null, COMPANY_EXIST);

        //判断账号是否已经存在
        User user = companyAndUser.getUser();
        user.setCompanyManager(true);
        User userInDb = UserService.getInstance().findUserByName(user.getName());
        VerifyUtil.verify(() -> userInDb == null, ACCOUNT_NAME_EXIST);

        //开始创建餐厅
        CommonService.getInstance().createObject(company, (Company c) -> {
            c.setCompanyId(company.getId());
            commonService.directSave(c);
        }, false, ResponseStatus.ACCOUNT_NAME_EXIST);

        //开始创建账号
        user.setName(user.getName().toLowerCase());
        UserService.getInstance().createUser(user);
        commonService.createObject(user, null, false, INVITE_EMAIL_EXIST);

        //添加个人和公司的映射
        UserCompanyMapping userCompanyMapping = new UserCompanyMapping();
        userCompanyMapping.setUserId(user.getId());
        userCompanyMapping.setCompanyId(company.getId());
        VerifyUtil.verify(() -> userCompanyMapping.getUserId() != null && userCompanyMapping.getCompanyId() != null);
        MappingService mappingService = MappingService.getInstance();
        mappingService.createUserCompanyMapping(userCompanyMapping.getUserId(), userCompanyMapping.getCompanyId());

        return ResponseData.emptyResponse();
    }

    @ApiOperation(value = "修改商家")
    @PutMapping(value = ("/company/modify"), produces = ("application/json;charset=UTF-8"))
    public ResponseData modify(@RequestBody Company company) throws Exception {
        //至少是个商家
        User user = ServletUtil.getUser();
        VerifyUtil.verify(() -> new Validator().isShopManager(user));

        VerifyUtil.verify(() -> new Validator().companyRelated(company.getId(), user), PRIVILEGE);

        //处理国际化
        if (company.getCompanyConfig() != null) {
            ZhEnService.getInstance().syncZhEn(company.getCompanyConfig());
            CompanyConfig companyConfig = company.getCompanyConfig();
            if (isNotEmpty(companyConfig.getSendNameInEmail())) {
                VerifyUtil.verify(() -> companyConfig.getSendNameInEmail().length() <= 15, SENDER_EMAIL_LENGTH_MORE_THAN_15, 15);
            }

            //如果要打开开关，那么需要校验配额
            CustomerService customerService = CustomerService.getInstance();
            if (getBoolean(companyConfig.getEmailToken())) {
                Optional<Quota> quotaOptional = customerService.findQuotaOrCreate(company.getId());
                VerifyUtil.verify(() -> quotaOptional.isPresent());
                Quota quota = quotaOptional.get();
                Integer canUsed = getInt(quota.getUnPlanEmailCanUsed());
                VerifyUtil.verify(() -> canUsed > 0, EMAIL_NOT_ENOUGH);
            }

            if (getBoolean(companyConfig.getPhoneToken())) {
                Optional<Quota> quotaOptional = customerService.findQuotaOrCreate(company.getId());
                VerifyUtil.verify(() -> quotaOptional.isPresent());
                Quota quota = quotaOptional.get();
                Integer canUsed = getInt(quota.getUnPlanSmsCanUsed());
                VerifyUtil.verify(() -> canUsed > 0, SMS_NOT_ENOUGH);
            }
        }

        ResponseData responseData = CommonService.getInstance().modifyObject(company);
        return responseData;
    }

    @Admin
    @ApiOperation(value = "删除商家")
    @DeleteMapping(value = ("/company"), produces = ("application/json;charset=UTF-8"))
    public ResponseData delete(@RequestBody Company company) throws Exception {
        //删除商家，采用真实删除
        ResponseData responseData = CommonService.getInstance().delete(company);

        //同步删除对应的账号
        UserService.getInstance().deleteUserInCompany(company);

        //同步删除映射关系
        CompanyService.getInstance().delete(company.getId(), UserCompanyMapping.class);
        return responseData;
    }

    @ApiOperation(value = "查询账号对应的公司")
    @PutMapping(value = ("/user/company"), produces = ("application/json;charset=UTF-8"))
    public ResponseData queryCompany(@RequestBody User user) throws Exception {
        VerifyUtil.verify(() -> user.getId() != null);
        Company company = CompanyService.getInstance().findCompanyByUserId(user.getId());
        if (company == null) {
            return ResponseData.emptyResponse();
        }

        return commonService.createResponse(company);
    }

}
